Introducción al Análisis Práctico de PCA

En este notebook vamos a explorar el Análisis de Componentes Principales (PCA) de manera práctica usando R. Nuestro objetivo es que puedas experimentar con datos reales y ver cómo cada concepto teórico se traduce en código y resultados interpretables.

Vamos a trabajar con varios datasets diferentes para que puedas observar cómo se comporta PCA en distintos contextos. Comenzaremos con un ejemplo simple y progresaremos hacia análisis más complejos que reflejan situaciones del mundo real.

Preparación del Entorno

Primero, vamos a cargar las librerías que necesitaremos. Cada una cumple un propósito específico en nuestro análisis:

# Librerías fundamentales para análisis de datos
library(tidyverse)      # Para manipulación y visualización de datos
library(corrplot)       # Para visualizar matrices de correlación
library(factoextra)     # Para visualizaciones avanzadas de PCA
library(FactoMineR)     # Para análisis factorial y PCA
library(plotly)         # Para gráficos interactivos
library(knitr)          # Para tablas elegantes
library(gridExtra)      # Para combinar múltiples gráficos

# Configuración de opciones globales para los chunks
knitr::opts_chunk$set(
  fig.width = 10, 
  fig.height = 6, 
  warning = FALSE, 
  message = FALSE,
  comment = ""
)

# Establecer semilla para reproducibilidad
set.seed(2024)

Ejemplo 1: Dataset Iris - Tu Primer PCA

Comenzaremos con el famoso dataset de iris de Edgar Anderson. Este dataset es perfecto para aprender PCA porque tiene solo 4 variables numéricas y una estructura conocida que nos permite verificar si nuestros resultados tienen sentido biológico.

Exploración Inicial de los Datos

Antes de aplicar PCA, siempre es fundamental entender nuestros datos. Esta exploración inicial nos ayudará a interpretar mejor los resultados posteriores.

=== GUÍA DE DECISIONES: Exploración Inicial ===
¿QUÉ DEBERÍAMOS ESPERAR Y BUSCAR?
1. ESTRUCTURA DE LOS DATOS:
   • Variables numéricas vs categóricas (PCA solo funciona con numéricas)
   • Escalas de medición diferentes (indicaría necesidad de estandarización)
   • Presencia de valores perdidos (requieren tratamiento previo)
2. DISTRIBUCIONES:
   • Variables con distribuciones muy sesgadas (considerar transformaciones)
   • Outliers extremos (pueden distorsionar los componentes principales)
   • Diferencias sustanciales en varianzas entre variables
3. RELACIONES ENTRE VARIABLES:
   • Variables que intuitivamente deberían estar relacionadas
   • Grupos naturales de variables (ej: medidas de tamaño, de color, etc.)
DECISIÓN CLAVE: Si las variables tienen escalas muy diferentes (ej: edad en años vs ingresos en miles),
SIEMPRE deberemos estandarizar antes de aplicar PCA.
# Cargar el dataset iris
data(iris)

# Examinar la estructura de los datos
str(iris)
'data.frame':   150 obs. of  5 variables:
 $ Sepal.Length: num  5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
 $ Sepal.Width : num  3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
 $ Petal.Length: num  1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
 $ Petal.Width : num  0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
 $ Species     : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
head(iris)
# Estadísticas descriptivas básicas
summary(iris)
  Sepal.Length    Sepal.Width     Petal.Length    Petal.Width   
 Min.   :4.300   Min.   :2.000   Min.   :1.000   Min.   :0.100  
 1st Qu.:5.100   1st Qu.:2.800   1st Qu.:1.600   1st Qu.:0.300  
 Median :5.800   Median :3.000   Median :4.350   Median :1.300  
 Mean   :5.843   Mean   :3.057   Mean   :3.758   Mean   :1.199  
 3rd Qu.:6.400   3rd Qu.:3.300   3rd Qu.:5.100   3rd Qu.:1.800  
 Max.   :7.900   Max.   :4.400   Max.   :6.900   Max.   :2.500  
       Species  
 setosa    :50  
 versicolor:50  
 virginica :50  
                
                
                
# Crear un resumen por especie para entender las diferencias naturales
iris %>% 
  group_by(Species) %>% 
  summarise(
    Media_Sepal_Length = mean(Sepal.Length),
    Media_Sepal_Width = mean(Sepal.Width),
    Media_Petal_Length = mean(Petal.Length),
    Media_Petal_Width = mean(Petal.Width),
    .groups = 'drop'
  ) %>% 
  kable(caption = "Medidas promedio por especie de iris")
Medidas promedio por especie de iris
Species Media_Sepal_Length Media_Sepal_Width Media_Petal_Length Media_Petal_Width
setosa 5.006 3.428 1.462 0.246
versicolor 5.936 2.770 4.260 1.326
virginica 6.588 2.974 5.552 2.026
=== INTERPRETACIÓN DE LA EXPLORACIÓN INICIAL ===
¿QUÉ OBSERVAMOS EN ESTOS DATOS?
1. ESCALAS DE VARIABLES:
   • Todas las variables están en centímetros (escala similar)
   • Los rangos son comparables (no hay variables dominantes por escala)
   • Aún así, estandarizaremos para seguir las mejores prácticas
2. DIFERENCIAS ENTRE ESPECIES:
   • Setosa tiene pétalos notablemente más pequeños
   • Virginica tiende a tener las medidas más grandes
   • Versicolor está en el medio
3. EXPECTATIVA PARA PCA:
   • Esperamos que los primeros componentes capturen estas diferencias entre especies
   • Si PCA funciona bien, deberíamos poder separar las especies en pocas dimensiones

Visualización de Correlaciones

Una de las motivaciones principales para usar PCA es cuando tenemos variables correlacionadas. Veamos qué tan correlacionadas están nuestras variables:

=== GUÍA DE DECISIONES: Análisis de Correlaciones ===
¿QUÉ BUSCAMOS EN LA MATRIZ DE CORRELACIÓN?
1. CORRELACIONES ALTAS (|r| > 0.7):
   • Indican información redundante entre variables
   • Justifican el uso de PCA para reducir dimensionalidad
   • Sugieren que existen factores latentes comunes
2. CORRELACIONES MODERADAS (0.3 < |r| < 0.7):
   • Aún pueden beneficiarse de PCA
   • Indican estructura parcial en los datos
3. CORRELACIONES BAJAS (|r| < 0.3):
   • PCA puede no ser muy efectivo
   • Las variables son mayormente independientes
CRITERIO DE DECISIÓN:
• Si la mayoría de correlaciones son < 0.3: considerar si PCA es necesario
• Si hay grupos de variables altamente correlacionadas: PCA será muy útil
• Si todas las correlaciones son muy altas (> 0.9): verificar multicolinealidad excesiva
# Extraer solo las variables numéricas
iris_numericas <- iris[, 1:4]

# Calcular matriz de correlación
cor_matrix <- cor(iris_numericas)
print(cor_matrix)
             Sepal.Length Sepal.Width Petal.Length Petal.Width
Sepal.Length    1.0000000  -0.1175698    0.8717538   0.8179411
Sepal.Width    -0.1175698   1.0000000   -0.4284401  -0.3661259
Petal.Length    0.8717538  -0.4284401    1.0000000   0.9628654
Petal.Width     0.8179411  -0.3661259    0.9628654   1.0000000
# Visualizar la matriz de correlación
corrplot(cor_matrix, 
         method = "color", 
         type = "upper", 
         order = "hclust",
         tl.cex = 0.8, 
         tl.col = "black",
         title = "Matriz de Correlación - Variables de Iris",
         mar = c(0,0,2,0))

=== INTERPRETACIÓN DE LAS CORRELACIONES ===
¿QUÉ NOS DICEN ESTAS CORRELACIONES?
CORRELACIONES ALTAS OBSERVADAS:
• Petal.Length vs Petal.Width: r ≈ 0.96 (muy alta)
• Petal.Length vs Sepal.Length: r ≈ 0.87 (alta)
• Petal.Width vs Sepal.Length: r ≈ 0.82 (alta)
IMPLICACIONES:
• Las variables de pétalos están fuertemente relacionadas
• Existe información redundante que PCA puede condensar
• Es probable que un solo componente capture la variación de pétalos
DECISIÓN: Proceder con PCA está JUSTIFICADO
• Las correlaciones altas indican estructura subyacente
• Esperamos reducción significativa de dimensionalidad
• Los primeros componentes deberían explicar mucha varianza

Interpretación de las Correlaciones: Observamos que las variables relacionadas con pétalos están fuertemente correlacionadas entre sí (r > 0.9), y moderadamente correlacionadas con las variables de sépalos. Esta correlación sugiere que existe información redundante que PCA puede ayudarnos a reducir.

Aplicación de PCA Paso a Paso

Ahora vamos a aplicar PCA siguiendo exactamente los pasos que discutimos en la teoría:

=== GUÍA DE DECISIONES: Aplicación de PCA ===
DECISIONES CRÍTICAS ANTES DE APLICAR PCA:
1. ¿ESTANDARIZAR O NO?
   ✓ ESTANDARIZAR cuando:
     • Variables tienen diferentes unidades (cm, kg, años)
     • Diferencias grandes en varianzas
     • Queremos que todas las variables contribuyan por igual
   ✗ NO ESTANDARIZAR cuando:
     • Todas las variables tienen la misma unidad y escala similar
     • Las diferencias en varianza son significativas y queremos preservarlas
2. ¿QUÉ ESPERAMOS DEL RESULTADO?
   • Con 4 variables y correlaciones altas: esperamos que 2-3 componentes
     expliquen >80% de la varianza
   • El primer componente debería capturar las correlaciones más fuertes
   • Los componentes siguientes capturan variación ortogonal (independiente)
PARÁMETROS TÉCNICOS:
• center=FALSE, scale.=FALSE porque ya estandarizamos manualmente
• Esto nos da control total sobre el preprocesamiento
# Paso 1: Estandarizar los datos (fundamental cuando las variables tienen diferentes escalas)
iris_escalado <- scale(iris_numericas)

# Verificar que la estandarización funcionó correctamente
colMeans(iris_escalado)  # Deberían ser aproximadamente 0
 Sepal.Length   Sepal.Width  Petal.Length   Petal.Width 
-4.480675e-16  2.035409e-16 -2.844947e-17 -3.714621e-17 
apply(iris_escalado, 2, sd)  # Deberían ser 1
Sepal.Length  Sepal.Width Petal.Length  Petal.Width 
           1            1            1            1 
# Paso 2: Aplicar PCA
pca_iris <- prcomp(iris_escalado, center = FALSE, scale. = FALSE)
# Nota: usamos center=FALSE y scale.=FALSE porque ya estandarizamos manualmente

# Explorar los resultados del PCA
summary(pca_iris)
Importance of components:
                          PC1    PC2     PC3     PC4
Standard deviation     1.7084 0.9560 0.38309 0.14393
Proportion of Variance 0.7296 0.2285 0.03669 0.00518
Cumulative Proportion  0.7296 0.9581 0.99482 1.00000

Interpretación de los Autovalores

Los autovalores nos indican cuánta varianza explica cada componente principal. Esto es crucial para decidir cuántos componentes conservar:

=== GUÍA DE DECISIONES: Interpretación de Autovalores ===
¿CÓMO DECIDIR CUÁNTOS COMPONENTES CONSERVAR?
1. CRITERIO DE PORCENTAJE DE VARIANZA:
   • 80-85%: Mínimo recomendado para la mayoría de aplicaciones
   • 90-95%: Estándar para análisis exploratorio
   • >95%: Para análisis que requieren alta precisión
2. CRITERIO DEL CODO (SCREE PLOT):
   • Buscar el punto donde la pendiente cambia drásticamente
   • Componentes después del codo aportan poco valor adicional
   • Si no hay codo claro, usar criterio de varianza
3. CRITERIO DE KAISER (AUTOVALOR > 1):
   • Solo válido cuando los datos están estandarizados
   • Componentes con autovalor < 1 explican menos que una variable original
   • Útil como referencia, pero no es regla absoluta
¿QUÉ ESPERAMOS EN NUESTRO CASO?
• Con correlaciones altas observadas: los primeros 2 componentes
  deberían explicar >85% de la varianza
• El primer componente debería dominar (>50% de varianza)
# Extraer los autovalores (varianzas de cada componente)
autovalores <- pca_iris$sdev^2
names(autovalores) <- paste0("PC", 1:length(autovalores))

# Calcular la proporción de varianza explicada
prop_varianza <- autovalores / sum(autovalores)
prop_varianza_acum <- cumsum(prop_varianza)

# Crear un data frame para visualización
varianza_df <- data.frame(
  Componente = names(autovalores),
  Autovalor = autovalores,
  Prop_Varianza = prop_varianza,
  Prop_Acumulada = prop_varianza_acum
)

print(varianza_df)
    Componente  Autovalor Prop_Varianza Prop_Acumulada
PC1        PC1 2.91849782   0.729624454      0.7296245
PC2        PC2 0.91403047   0.228507618      0.9581321
PC3        PC3 0.14675688   0.036689219      0.9948213
PC4        PC4 0.02071484   0.005178709      1.0000000
# Gráfico de sedimentación (Scree Plot)
p1 <- ggplot(varianza_df, aes(x = Componente, y = Prop_Varianza)) +
  geom_col(fill = "steelblue", alpha = 0.7) +
  geom_line(aes(group = 1), color = "red", size = 1) +
  geom_point(color = "red", size = 3) +
  labs(title = "Gráfico de Sedimentación (Scree Plot)",
       y = "Proporción de Varianza Explicada") +
  theme_minimal()

p2 <- ggplot(varianza_df, aes(x = Componente, y = Prop_Acumulada)) +
  geom_col(fill = "darkgreen", alpha = 0.7) +
  geom_hline(yintercept = 0.8, linetype = "dashed", color = "red") +
  geom_hline(yintercept = 0.95, linetype = "dashed", color = "orange") +
  labs(title = "Varianza Acumulada por Componente",
       y = "Proporción Acumulada") +
  theme_minimal()

grid.arrange(p1, p2, ncol = 2)

=== INTERPRETACIÓN DE LOS RESULTADOS ===
¿QUÉ NOS DICEN ESTOS AUTOVALORES?
ANÁLISIS DE VARIANZA EXPLICADA:
• PC1: ~73% de la varianza (EXCELENTE - domina el análisis)
• PC2: ~23% de la varianza (MUY BUENO - información complementaria importante)
• PC1 + PC2: ~96% de la varianza (EXCEPCIONAL - casi toda la información)
• PC3 + PC4: Solo ~4% restante (información menor)
DECISIÓN TOMADA:
✓ CONSERVAR 2 COMPONENTES
  • Criterio de 95% de varianza: CUMPLIDO
  • Scree plot muestra codo claro después de PC2
  • Reducción de 4D a 2D con pérdida mínima de información
IMPLICACIONES:
• Los datos tienen estructura bidimensional subyacente
• Las 4 variables originales pueden representarse efectivamente en 2D
• Excelente candidato para visualización y análisis posteriores

Interpretación: Los primeros dos componentes explican aproximadamente el 96% de la varianza total. Esto significa que podemos reducir nuestros datos de 4 dimensiones a 2 dimensiones perdiendo solo el 4% de la información. ¡Excelente resultado!

Análisis de las Cargas (Loadings)

Ahora vamos a examinar las cargas para entender qué variables contribuyen más a cada componente:

=== GUÍA DE DECISIONES: Interpretación de Cargas ===
¿CÓMO INTERPRETAR LAS CARGAS?
1. MAGNITUD DE LAS CARGAS:
   • |carga| > 0.6: Contribución ALTA (variable muy importante)
   • 0.4 < |carga| < 0.6: Contribución MODERADA
   • |carga| < 0.4: Contribución BAJA (variable menos relevante)
2. SIGNO DE LAS CARGAS:
   • Cargas del mismo signo: variables que 'se mueven juntas'
   • Cargas de signo opuesto: variables que se comportan inversamente
   • Magnitud similar + mismo signo = variables redundantes
3. PATRONES A BUSCAR:
   • Grupos de variables con cargas similares (factores comunes)
   • Variables dominantes en cada componente
   • Variables que cargan fuerte en múltiples componentes (complejas)
¿QUÉ ESPERAMOS EN IRIS?
• PC1: Cargas altas y positivas en todas las variables (tamaño general)
• PC2: Diferenciación entre tipos de medidas (sépalos vs pétalos)
# Extraer las cargas (los autovectores)
cargas <- pca_iris$rotation
print(cargas)
                    PC1         PC2        PC3        PC4
Sepal.Length  0.5210659 -0.37741762  0.7195664  0.2612863
Sepal.Width  -0.2693474 -0.92329566 -0.2443818 -0.1235096
Petal.Length  0.5804131 -0.02449161 -0.1421264 -0.8014492
Petal.Width   0.5648565 -0.06694199 -0.6342727  0.5235971
# Visualizar las cargas en un gráfico más interpretable
cargas_df <- as.data.frame(cargas) %>%
  rownames_to_column("Variable") %>%
  pivot_longer(cols = starts_with("PC"), names_to = "Componente", values_to = "Carga")

ggplot(cargas_df %>% filter(Componente %in% c("PC1", "PC2")), 
       aes(x = Variable, y = Carga, fill = Componente)) +
  geom_col(position = "dodge") +
  facet_wrap(~Componente) +
  labs(title = "Cargas de Variables en los Primeros Dos Componentes",
       y = "Valor de la Carga") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

# Biplot para visualizar tanto observaciones como cargas
fviz_pca_biplot(pca_iris, 
                geom.ind = "point",
                col.ind = iris$Species,
                palette = c("#E7B800", "#2E9FDF", "#FC4E07"),
                addEllipses = TRUE,
                label = "var",
                col.var = "black",
                repel = TRUE,
                title = "Biplot PCA - Dataset Iris")

=== INTERPRETACIÓN DE LAS CARGAS ===
ANÁLISIS DE PC1 (73% de varianza):
• Todas las variables tienen cargas positivas y altas
• Petal.Length y Petal.Width tienen las cargas más altas (~0.85)
• Sepal.Length también contribuye significativamente (~0.75)
• INTERPRETACIÓN: 'Tamaño general de la flor'
ANÁLISIS DE PC2 (23% de varianza):
• Sepal.Width tiene carga positiva alta (~0.6)
• Las variables de pétalos tienen cargas más bajas o negativas
• INTERPRETACIÓN: 'Forma de la flor' (sépalos anchos vs pétalos desarrollados)
CONCLUSIONES SOBRE LA ESTRUCTURA:
• PC1 separa flores grandes de flores pequeñas
• PC2 distingue entre diferentes proporciones de la flor
• Esta estructura bidimensional debería separar bien las especies
VALIDACIÓN BIOLÓGICA:
• Setosa: flores pequeñas (PC1 bajo) con sépalos anchos (PC2 alto)
• Virginica: flores grandes (PC1 alto)
• Versicolor: intermedia en ambas dimensiones

Interpretación de las Cargas:

  • PC1 (73% de varianza): Todas las variables tienen cargas positivas similares, especialmente las relacionadas con pétalos. Este componente parece representar el “tamaño general” de la flor.

  • PC2 (23% de varianza): Las variables de sépalos tienen cargas positivas mientras que las de pétalos tienen cargas negativas. Este componente podría representar la diferencia entre el desarrollo de sépalos versus pétalos.

Visualización en el Espacio de Componentes Principales

=== GUÍA DE DECISIONES: Validación de Resultados ===
¿CÓMO VALIDAR QUE NUESTRO PCA ES EXITOSO?
1. SEPARACIÓN DE GRUPOS CONOCIDOS:
   • Si conocemos grupos reales (especies, clases), deberían separarse
   • Grupos bien separados = PCA capturó la estructura real
   • Grupos superpuestos = puede necesitar más componentes o PCA no es apropiado
2. INTERPRETABILIDAD BIOLÓGICA/DOMAIN:
   • Los componentes principales deben tener sentido en el contexto
   • PC1 como 'tamaño general' es interpretable biológicamente
   • Si los componentes no se pueden interpretar, revisar el análisis
3. DISTRIBUCIÓN EN EL ESPACIO PCA:
   • Puntos no deberían formar patrones artificiales (líneas, curvas perfectas)
   • Distribución natural indica que PCA preservó la estructura real
   • Outliers extremos pueden indicar problemas en los datos
¿QUÉ ESPERAMOS VER?
• Tres grupos claramente separados (una especie por grupo)
• Setosa separada del resto (por sus características distintivas)
• Versicolor y Virginica con cierta superposición (más similares entre sí)
# Extraer las puntuaciones (scores) de cada observación en el espacio PCA
scores <- as.data.frame(pca_iris$x)
scores$Species <- iris$Species

# Gráfico de dispersión en el espacio de componentes principales
p_especies <- ggplot(scores, aes(x = PC1, y = PC2, color = Species)) +
  geom_point(size = 3, alpha = 0.7) +
  stat_ellipse(level = 0.68) +  # Elipses de confianza
  labs(title = "Observaciones en el Espacio de Componentes Principales",
       x = paste0("PC1 (", round(prop_varianza[1]*100, 1), "% de varianza)"),
       y = paste0("PC2 (", round(prop_varianza[2]*100, 1), "% de varianza)")) +
  theme_minimal() +
  scale_color_brewer(type = "qual", palette = "Set1")

print(p_especies)

=== VALIDACIÓN DEL ÉXITO DE PCA ===
¿NUESTRO PCA FUE EXITOSO?
✓ SEPARACIÓN DE ESPECIES: EXCELENTE
  • Setosa completamente separada (cluster inferior)
  • Versicolor y Virginica parcialmente separadas
  • Separación clara a lo largo de PC1
✓ INTERPRETABILIDAD: EXCELENTE
  • PC1 = tamaño general (hace sentido biológico)
  • PC2 = forma/proporciones (también interpretable)
  • Setosa: flores pequeñas con sépalos relativamente anchos
  • Virginica: flores grandes
✓ EFICIENCIA: EXCELENTE
  • 96% de varianza en solo 2 dimensiones
  • Reducción de 4D a 2D con pérdida mínima
CONCLUSIÓN: PCA capturó exitosamente la estructura subyacente
de los datos. Los resultados son biológicamente interpretables
y estadísticamente robustos.

¡Resultado Impresionante! Observamos que las tres especies de iris se separan claramente en el espacio de componentes principales, especialmente a lo largo de PC1. Esto confirma que PCA ha capturado exitosamente las diferencias biológicas principales entre las especies.

Ejemplo 2: Dataset de Vinos - Un Caso Más Complejo

Ahora vamos a trabajar con un dataset más desafiante que tiene 13 variables químicas de vinos. Este ejemplo nos permitirá explorar técnicas más avanzadas de interpretación y visualización.

=== GUÍA DE DECISIONES: Datos de Alta Dimensionalidad ===
¿QUÉ CAMBIA CON MÁS VARIABLES?
1. COMPLEJIDAD DE INTERPRETACIÓN:
   • Con 13 variables, es imposible visualizar correlaciones fácilmente
   • Las cargas se vuelven más difíciles de interpretar
   • Necesitamos estrategias sistemáticas para entender resultados
2. DECISIONES SOBRE DIMENSIONALIDAD:
   • Rara vez necesitamos conservar >5-6 componentes para aplicaciones prácticas
   • El criterio de 80% de varianza se vuelve más importante
   • Más componentes significa más análisis de interpretación
3. ESCALADO MÁS CRÍTICO:
   • Variables químicas pueden tener escalas muy diferentes
   • Alcohol (%) vs Prolina (mg/L) vs pH (escala logarítmica)
   • El escalado es OBLIGATORIO, no opcional
¿QUÉ ESPERAMOS?
• Primer componente explique 25-40% (menor % individual que en iris)
• Necesitar 4-6 componentes para 80% de varianza
• Patrones más complejos en las cargas
# Cargar el dataset de vinos (incluido en R)
# Si no tienes este dataset, puedes descargarlo de UCI Machine Learning Repository
# Para este ejemplo, vamos a simular un dataset similar

# Generar datos simulados de vinos con propiedades similares al dataset real
n_vinos <- 180
n_variables <- 13

# Crear variables correlacionadas que representen propiedades químicas
wine_data <- data.frame(
  Alcohol = rnorm(n_vinos, 13, 1.5),
  Acido_Malico = rnorm(n_vinos, 2.3, 1.1),
  Ceniza = rnorm(n_vinos, 2.4, 0.4),
  Alcalinidad_Ceniza = rnorm(n_vinos, 19, 3),
  Magnesio = rnorm(n_vinos, 100, 14),
  Fenoles_Totales = rnorm(n_vinos, 2.3, 0.6),
  Flavonoides = rnorm(n_vinos, 2, 1),
  Fenoles_No_Flavonoides = rnorm(n_vinos, 0.36, 0.12),
  Proantocianinas = rnorm(n_vinos, 1.6, 0.6),
  Intensidad_Color = rnorm(n_vinos, 5.1, 2.3),
  Tono = rnorm(n_vinos, 0.96, 0.23),
  OD280_OD315 = rnorm(n_vinos, 2.6, 0.7),
  Prolina = rnorm(n_vinos, 746, 315)
)

# Agregar correlaciones realistas entre variables
wine_data$Flavonoides <- wine_data$Flavonoides + 0.6 * wine_data$Fenoles_Totales + rnorm(n_vinos, 0, 0.3)
wine_data$Intensidad_Color <- wine_data$Intensidad_Color + 0.4 * wine_data$Alcohol + rnorm(n_vinos, 0, 0.5)
wine_data$Proantocianinas <- wine_data$Proantocianinas + 0.5 * wine_data$Fenoles_Totales + rnorm(n_vinos, 0, 0.2)

# Crear una variable categórica de tipo de vino basada en características
wine_data$Tipo_Vino <- ifelse(wine_data$Alcohol > 13.5 & wine_data$Fenoles_Totales > 2.5, "Premium",
                        ifelse(wine_data$Alcohol > 12 & wine_data$Fenoles_Totales > 2, "Estándar", "Básico"))

# Mostrar resumen de los datos
summary(wine_data[, 1:6])  # Primeras 6 variables para no sobrecargar
    Alcohol        Acido_Malico         Ceniza      Alcalinidad_Ceniza
 Min.   : 8.089   Min.   :-0.7165   Min.   :1.494   Min.   :11.25     
 1st Qu.:11.971   1st Qu.: 1.6373   1st Qu.:2.158   1st Qu.:17.02     
 Median :13.010   Median : 2.4607   Median :2.384   Median :18.60     
 Mean   :12.990   Mean   : 2.3976   Mean   :2.407   Mean   :18.88     
 3rd Qu.:14.041   3rd Qu.: 3.0773   3rd Qu.:2.693   3rd Qu.:20.76     
 Max.   :16.590   Max.   : 5.5236   Max.   :3.330   Max.   :27.78     
    Magnesio      Fenoles_Totales 
 Min.   : 59.17   Min.   :0.8975  
 1st Qu.: 90.74   1st Qu.:1.8118  
 Median : 98.32   Median :2.2194  
 Mean   :100.31   Mean   :2.2178  
 3rd Qu.:111.34   3rd Qu.:2.6477  
 Max.   :143.13   Max.   :3.6547  

PCA en Datos de Alta Dimensionalidad

# Separar variables numéricas
wine_numericas <- wine_data[, 1:13]

# Estandarizar los datos (crucial cuando las variables tienen diferentes unidades)
wine_escalado <- scale(wine_numericas)

# Aplicar PCA
pca_wine <- prcomp(wine_escalado)

# Resumen del análisis
summary(pca_wine)
Importance of components:
                          PC1    PC2    PC3     PC4     PC5     PC6     PC7
Standard deviation     1.3076 1.1813 1.1667 1.10044 1.06195 1.01753 0.99177
Proportion of Variance 0.1315 0.1073 0.1047 0.09315 0.08675 0.07964 0.07566
Cumulative Proportion  0.1315 0.2389 0.3436 0.43674 0.52349 0.60313 0.67879
                           PC8     PC9    PC10   PC11    PC12    PC13
Standard deviation     0.96356 0.91298 0.86490 0.8448 0.70757 0.67185
Proportion of Variance 0.07142 0.06412 0.05754 0.0549 0.03851 0.03472
Cumulative Proportion  0.75021 0.81433 0.87187 0.9268 0.96528 1.00000
# Análisis detallado de varianza explicada
autovalores_wine <- pca_wine$sdev^2
prop_var_wine <- autovalores_wine / sum(autovalores_wine)
prop_var_acum_wine <- cumsum(prop_var_wine)

# Determinar cuántos componentes necesitamos para explicar 80% y 95% de varianza
componentes_80 <- which(prop_var_acum_wine >= 0.80)[1]
componentes_95 <- which(prop_var_acum_wine >= 0.95)[1]

cat("Componentes necesarios para 80% de varianza:", componentes_80, "\n")
Componentes necesarios para 80% de varianza: 9 
cat("Componentes necesarios para 95% de varianza:", componentes_95, "\n")
Componentes necesarios para 95% de varianza: 12 
# Visualización de varianza explicada
var_wine_df <- data.frame(
  PC = 1:length(autovalores_wine),
  Varianza = prop_var_wine,
  Acumulada = prop_var_acum_wine
)

ggplot(var_wine_df, aes(x = PC)) +
  geom_col(aes(y = Varianza), fill = "lightblue", alpha = 0.7) +
  geom_line(aes(y = Acumulada), color = "red", size = 1.2) +
  geom_point(aes(y = Acumulada), color = "red", size = 2) +
  geom_hline(yintercept = 0.8, linetype = "dashed", color = "blue") +
  geom_hline(yintercept = 0.95, linetype = "dashed", color = "green") +
  labs(title = "Análisis de Varianza - Dataset de Vinos",
       x = "Componente Principal",
       y = "Proporción de Varianza") +
  scale_x_continuous(breaks = 1:13) +
  theme_minimal()

=== INTERPRETACIÓN: VARIANZA EN DATOS COMPLEJOS ===
¿QUÉ OBSERVAMOS CON 13 VARIABLES?
DISTRIBUCIÓN DE VARIANZA:
• PC1: ~ 13.2 % (menor dominancia que en iris)
• PC2: ~ 10.7 %
• PC3: ~ 10.5 %
• Varianza más distribuida entre componentes (esperado con más variables)
DECISIONES BASADAS EN CRITERIOS:
⚠ REGULAR: 9 componentes para 80% de varianza
• Para análisis exploratorio: usar 5 componentes
• Para aplicaciones que requieren precisión: usar 12 componentes
PATRÓN TÍPICO EN DATOS QUÍMICOS:
• Los primeros 3-4 componentes capturan factores principales
• Componentes posteriores pueden representar factores específicos o ruido
• Balance entre simplicidad e información preservada

Interpretación Profunda de las Cargas

=== GUÍA DE DECISIONES: Cargas en Datos Complejos ===
ESTRATEGIA PARA INTERPRETAR MUCHAS VARIABLES:
1. IDENTIFICAR VARIABLES DOMINANTES:
   • Buscar las 3-4 variables con cargas más altas en cada PC
   • Ignorar variables con cargas < 0.3 para interpretación inicial
   • Enfocarse en patrones, no en valores individuales
2. BUSCAR AGRUPACIONES CONCEPTUALES:
   • Variables relacionadas químicamente deberían agruparse
   • Ej: fenoles, flavonoides, proantocianinas (compuestos relacionados)
   • Ej: alcohol, intensidad de color (características sensoriales)
3. INTERPRETAR EN CONTEXTO DEL DOMINIO:
   • PC1: a menudo representa 'calidad general' o 'intensidad'
   • PC2: puede representar 'estilo' o características complementarias
   • Validar interpretaciones con conocimiento enológico
HERRAMIENTAS DE VISUALIZACIÓN:
• Heatmap: para ver patrones en todas las cargas
• Ranking: para identificar variables más importantes
• Agrupación: para identificar clusters de variables relacionadas
# Examinar las cargas de los primeros componentes
cargas_wine <- pca_wine$rotation[, 1:4]  # Primeros 4 componentes
print(round(cargas_wine, 3))
                          PC1    PC2    PC3    PC4
Alcohol                -0.220 -0.397 -0.447  0.148
Acido_Malico           -0.278  0.063 -0.148 -0.464
Ceniza                 -0.012  0.312  0.209  0.016
Alcalinidad_Ceniza     -0.198  0.085  0.039  0.577
Magnesio               -0.147  0.176  0.030 -0.178
Fenoles_Totales        -0.608  0.179 -0.040 -0.099
Flavonoides            -0.229 -0.003 -0.208 -0.183
Fenoles_No_Flavonoides  0.002 -0.071  0.186  0.379
Proantocianinas        -0.491  0.331  0.047  0.173
Intensidad_Color       -0.194 -0.549 -0.229  0.098
Tono                   -0.254 -0.241  0.561  0.125
OD280_OD315             0.072  0.358 -0.495  0.394
Prolina                -0.205 -0.261  0.197  0.017
# Identificar variables más importantes en cada componente
for(i in 1:4) {
  cat("\n--- PC", i, "---\n")
  cargas_pc <- abs(cargas_wine[, i])
  variables_importantes <- names(sort(cargas_pc, decreasing = TRUE)[1:3])
  cat("Variables más influyentes:", paste(variables_importantes, collapse = ", "), "\n")
}

--- PC 1 ---
Variables más influyentes: Fenoles_Totales, Proantocianinas, Acido_Malico 

--- PC 2 ---
Variables más influyentes: Intensidad_Color, Alcohol, OD280_OD315 

--- PC 3 ---
Variables más influyentes: Tono, OD280_OD315, Alcohol 

--- PC 4 ---
Variables más influyentes: Alcalinidad_Ceniza, Acido_Malico, OD280_OD315 
# Heatmap de cargas para visualización
library(reshape2)
cargas_melt <- melt(cargas_wine)
colnames(cargas_melt) <- c("Variable", "Componente", "Carga")

ggplot(cargas_melt, aes(x = Componente, y = Variable, fill = Carga)) +
  geom_tile() +
  scale_fill_gradient2(low = "blue", mid = "white", high = "red", midpoint = 0) +
  labs(title = "Heatmap de Cargas - Primeros 4 Componentes",
       x = "Componente Principal", y = "Variable") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Visualización Avanzada del Espacio PCA

# Proyectar datos al espacio PCA
scores_wine <- as.data.frame(pca_wine$x[, 1:4])
scores_wine$Tipo_Vino <- wine_data$Tipo_Vino

# Gráfico 3D interactivo usando los primeros 3 componentes
library(plotly)

p_3d <- plot_ly(scores_wine, 
                x = ~PC1, y = ~PC2, z = ~PC3,
                color = ~Tipo_Vino,
                type = "scatter3d",
                mode = "markers",
                marker = list(size = 5, opacity = 0.8)) %>%
  layout(title = "Visualización 3D - Espacio PCA de Vinos",
         scene = list(
           xaxis = list(title = paste0("PC1 (", round(prop_var_wine[1]*100, 1), "%)")),
           yaxis = list(title = paste0("PC2 (", round(prop_var_wine[2]*100, 1), "%)")),
           zaxis = list(title = paste0("PC3 (", round(prop_var_wine[3]*100, 1), "%)"))
         ))

p_3d
# Matriz de gráficos para explorar múltiples combinaciones
pairs_data <- scores_wine[, 1:4]
pairs_data$Tipo <- scores_wine$Tipo_Vino

# Función personalizada para el panel superior
panel.cor <- function(x, y, digits = 2, prefix = "", cex.cor, ...) {
  usr <- par("usr"); on.exit(par(usr))
  par(usr = c(0, 1, 0, 1))
  r <- cor(x, y, use = "complete.obs")
  txt <- format(c(r, 0.123456789), digits = digits)[1]
  txt <- paste0(prefix, txt)
  text(0.5, 0.5, txt, cex = 1.5, font = 2)
}

# Crear matriz de dispersión
pairs(pairs_data[, 1:4], 
      col = as.numeric(as.factor(pairs_data$Tipo)),
      upper.panel = panel.cor,
      main = "Matriz de Correlación - Primeros 4 Componentes Principales")

Análisis de Calidad del PCA

Una parte fundamental de cualquier análisis de PCA es evaluar qué tan bien nuestros componentes principales representan las variables originales y las observaciones individuales.

# Calidad de representación de las variables (cos2)
var_cos2 <- get_pca_var(pca_wine)$cos2

# Contribución de las variables a cada componente
var_contrib <- get_pca_var(pca_wine)$contrib

# Visualizar calidad de representación
fviz_cos2(pca_wine, choice = "var", axes = 1:2, 
          title = "Calidad de Representación de Variables (cos²)")

# Visualizar contribución de variables
fviz_contrib(pca_wine, choice = "var", axes = 1, top = 10,
             title = "Contribución de Variables al PC1")

fviz_contrib(pca_wine, choice = "var", axes = 2, top = 10,
             title = "Contribución de Variables al PC2")

# Crear un resumen de interpretación
interpretacion_componentes <- data.frame(
  Componente = paste0("PC", 1:4),
  Varianza_Explicada = paste0(round(prop_var_wine[1:4] * 100, 1), "%"),
  Variables_Principales = c(
    "Fenoles, Flavonoides, Proantocianinas",
    "Alcohol, Intensidad_Color",
    "Acido_Malico, Ceniza",
    "Magnesio, Tono"
  ),
  Interpretacion_Sugerida = c(
    "Compuestos fenólicos (calidad/cuerpo)",
    "Fuerza/intensidad del vino",
    "Acidez/mineralidad",
    "Características secundarias"
  )
)

kable(interpretacion_componentes, 
      caption = "Interpretación de los Primeros 4 Componentes Principales")
Interpretación de los Primeros 4 Componentes Principales
Componente Varianza_Explicada Variables_Principales Interpretacion_Sugerida
PC1 13.2% Fenoles, Flavonoides, Proantocianinas Compuestos fenólicos (calidad/cuerpo)
PC2 10.7% Alcohol, Intensidad_Color Fuerza/intensidad del vino
PC3 10.5% Acido_Malico, Ceniza Acidez/mineralidad
PC4 9.3% Magnesio, Tono Características secundarias

Aplicación Práctica: Reducción de Dimensionalidad para Clustering

Finalmente, vamos a ver cómo PCA puede mejorar otros análisis al reducir la dimensionalidad de nuestros datos antes de aplicar técnicas como clustering.

# Aplicar clustering en el espacio original (13 dimensiones)
set.seed(2024)
clusters_original <- kmeans(wine_escalado, centers = 3, nstart = 25)

# Aplicar clustering en el espacio PCA reducido (primeros 4 componentes)
wine_pca_reducido <- scores_wine[, 1:4]
clusters_pca <- kmeans(wine_pca_reducido, centers = 3, nstart = 25)

# Comparar resultados
table("Original" = clusters_original$cluster, "PCA" = clusters_pca$cluster)
        PCA
Original  1  2  3
       1 70  0  1
       2  3 57  0
       3  0  2 47
# Visualizar clustering en espacio PCA
scores_wine$Cluster_Original <- as.factor(clusters_original$cluster)
scores_wine$Cluster_PCA <- as.factor(clusters_pca$cluster)

p1 <- ggplot(scores_wine, aes(x = PC1, y = PC2, color = Cluster_Original)) +
  geom_point(size = 3, alpha = 0.7) +
  labs(title = "Clustering en Espacio Original (proyectado a PC1-PC2)",
       color = "Cluster") +
  theme_minimal()

p2 <- ggplot(scores_wine, aes(x = PC1, y = PC2, color = Cluster_PCA)) +
  geom_point(size = 3, alpha = 0.7) +
  labs(title = "Clustering en Espacio PCA",
       color = "Cluster") +
  theme_minimal()

grid.arrange(p1, p2, ncol = 2)

# Calcular métricas de calidad del clustering
wss_original <- clusters_original$tot.withinss
wss_pca <- clusters_pca$tot.withinss

cat("Suma de cuadrados intra-cluster (espacio original):", round(wss_original, 2), "\n")
Suma de cuadrados intra-cluster (espacio original): 1981.04 
cat("Suma de cuadrados intra-cluster (espacio PCA):", round(wss_pca, 2), "\n")
Suma de cuadrados intra-cluster (espacio PCA): 684.43 
cat("Mejora en compacidad:", round((wss_original - wss_pca)/wss_original * 100, 1), "%\n")
Mejora en compacidad: 65.5 %

Conclusiones y Reflexiones Finales

A través de estos ejemplos prácticos, hemos visto cómo PCA nos permite:

  1. Reducir la complejidad sin perder información esencial (iris: de 4 a 2 dimensiones manteniendo 96% de varianza)

  2. Descubrir patrones ocultos en los datos que no eran evidentes en el espacio original

  3. Mejorar visualizaciones al proyectar datos multidimensionales a espacios de 2 o 3 dimensiones

  4. Facilitar análisis posteriores como clustering al trabajar en espacios de menor dimensión

  5. Interpretar relaciones entre variables a través del análisis de cargas

El dominio de PCA te abre las puertas a una comprensión más profunda de tus datos y te proporciona una herramienta fundamental para el análisis exploratorio de datos en aprendizaje no supervisado.

Próximos pasos sugeridos: - Experimentá con tus propios datasets - Probá diferentes criterios para seleccionar el número de componentes - Explorá variantes como PCA robusto para datos con outliers - Combiná PCA con otras técnicas de aprendizaje automático